/*
 *   Clovis
 *   Copyright (C) 2008 SFWOL
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "XMLFileReader.h"

namespace clovis {

	namespace datas {

		XMLFileReader::XMLFileReader(core::CString input_file){

			// Init of the internal variables
			this->tree = new core::Tree();

			this->tags = 0;
			this->single_tags = 0;
			this->attributes = 0;
			this->max_depth = 0;
			this->errors = 0;
			this->warning = 0;
			this->file = input_file;
			this->current_depth = 0;
			this->current_line = 0;

			std::ifstream file( input_file.toCharArray() );

			if(file){

				std::string line;

				while (std::getline(file, line)){

					this->current_line++;
					this->parseLine(line);

				}

			}else{

				//this = NULL;

				core::CString error = "File not found : " + input_file.toStdString();
				io::Log::logOn(io::WARNING,error);

			}

		}

		void XMLFileReader::parseLine(core::CString line){

			unsigned int bcl = 0;
			core::CString inner_tag;
			core::CString tag_name = "";

			line.wash();

			// 1. Explode the line with '<'
			std::vector<core::CString> hash = line.explode("<");

			// If there is at least 2 elements
			// OR If there is only 1 element but with a '>' char
			if(hash.size() > 1 || ( hash.size() == 1 && hash[0].findFirstOf(">") != -1 )){

				// There is a least one tag in this line

				bcl = 0;
				while(bcl <= hash.size() - 1){

					// Looking into the found tag
					inner_tag = hash[bcl];

					if(inner_tag.charAt(0) == '/'){

						// Ending tag

						// Saving maximum depth
						if(this->current_depth > this->max_depth)
							this->max_depth = this->current_depth;

						tag_name = getTagName(inner_tag);

						if(this->ariane[this->ariane.size() - 1] != tag_name){

							std::cout << "[ERROR] XMLFileReader : Unclosed tag found at line " << this->current_line.toInt() << std::endl;
							this->errors++;

						}else{

							this->ariane.pop_back();

						}

						this->current_depth--;


					}else{

						// Starting tag

						if(inner_tag.charAt(inner_tag.findLastOf("/")+1) == '>'){

							this->single_tags++;
							parseAttributes(inner_tag);
							tag_name = getTagName(inner_tag);

						}else{

							this->tags++;
							parseAttributes(inner_tag);
							tag_name = getTagName(inner_tag);
							this->ariane.push_back(tag_name);

							this->current_depth++;

						}

					}

					bcl++;

				}

			}else{

				if(line.size() > 0){

					// There is something in this line

					//std::cout << "Not empty" << std::endl;

				}

			} // END OF : if(hash.size() > 1 || ( hash.size() == 1 && hash[0].findFirstOf(">") != -1 ))

		}

		core::CString XMLFileReader::getTagName(core::CString tag){

			std::vector<core::CString> elts = tag.explode("<");

			elts = elts[0].explode(">");
			elts = elts[0].explode("/");
			elts = elts[0].explode(" ");

			return elts[0];

		}

		void XMLFileReader::parseAttributes(core::CString tag){

			core::CString current_attribute;
			core::CString attribute_name;
			core::CString attribute_value;

			if(tag.findFirstOf(" ") != -1){

				std::vector<core::CString> hash = tag.explode(" ");

				core::CInteger bcl = 0;
				while(bcl <= hash.size() - 1){

					if(bcl != 0){

						// The first element is the node's name

						current_attribute = hash[bcl.toInt()];

						std::vector<core::CString> att_hash = current_attribute.explode("=");
						attribute_name = att_hash[0];

						att_hash = att_hash[1].explode("\"");
						attribute_value = att_hash[0];

						//std::cout << "Attribute[" << attribute_name.toCharArray() << "] = " << attribute_value.toCharArray() << std::endl;

						this->attributes++;


					}

					bcl++;

				}

			}

		}

		void XMLFileReader::showReport(bool verbose){

			std::cout << std::endl;
			std::cout << "=======================================" << std::endl;
			std::cout << "| clovis::datas::XMLFileReader Report |" << std::endl;
			std::cout << "=======================================" << std::endl;
			std::cout << std::endl;
			std::cout << "File : '" << this->file.toCharArray() << "'" << std::endl;
			std::cout << std::endl;

			if(verbose){

				std::cout << "Number of tags         <foo></foo> : " << this->tags.toInt() << std::endl;
				std::cout << "Number of single tags  <foo/>      : " << this->single_tags.toInt() << std::endl;
				std::cout << "Number of attributes               : " << this->attributes.toInt() << std::endl;
				std::cout << "Maximum depth                      : " << this->max_depth.toInt() << std::endl;
				std::cout << std::endl;

			}

			std::cout << this->errors.toInt() << " Error(s) and " << this->warning.toInt() << " Warning(s) encountered" << std::endl;
			std::cout << std::endl;
			std::cout << "============ End of Report ============" << std::endl;
			std::cout << std::endl;

		}

	};

};
